<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>UDB Waypoint Editor</title>
    <style type="text/css">
     body { margin: 0px; padding: 0px }
    </style>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
	
    <script type="text/javascript">
		var map;
		var waypoints; //Waypoints on the map
		var cameras; // Camera markers on the map
		var infoWindow = new google.maps.InfoWindow();
		var infoWindowVisible = false;
		var clickMode = "waypoint";
		var waypointDefIndex;
		var waypointDefLen;
		var camerasDefIndex;
		var camerasDefLen;
		var overlayArray = []; // array of overlays on the map
		var waypointsHaveFocus = false;
		var homePoint = new google.maps.LatLng(0, 0);
		
		var homeMarker;

    function getHomePoint(){
      try{
        var lat;
        lat = get_cookie("UDB_home_lat");
        var lng;
        lng = get_cookie("UDB_home_lng");
//alert(lat + "\n" + lng);
        if ((lat && lng) && !((lat == "null") || (lng == "null"))) {
          if (lng != "") { // both have to be non-null before we can use them
//alert("Setting home from cookie\n" + lat + "\n" + lng);
            homePoint = new google.maps.LatLng(lat, lng);
          }
        }
      } catch(err) {
        alert("Your browser security settings don't allow cookies. Home location won't be saved.\nTry using #define FIXED_ORIGIN_LOCATION {-1219950467, 374124664} in your waypoints file to set home location.");
      }
      setHomeMarker();
    }
	
	var oldHomePointLat;
	var oldHomePointLng;
	
    function setHomeMarker(){
      homeMarker = new google.maps.Marker({position: homePoint, draggable: true}); // TODO: Custom icon for home point
      google.maps.event.addListener(homeMarker, "dragend", homeMarkerMoved);
      google.maps.event.addListener(homeMarker, "dragstart", function() {
		infoWindow.close();
		oldHomePointLat = homePoint.lat();
		oldHomePointLng = homePoint.lng();
      });
    }

    function homeMarkerMoved(){
      //TODO: Ask if the waypoints should be updated or not.
      homePoint = homeMarker.getPosition();
		saveHomePoint();
		reloadWaypointsHeader();
      //markerMoved();
    }

    function saveHomePoint(){
      set_cookie("UDB_home_lat", homePoint.lat());
      set_cookie("UDB_home_lng", homePoint.lng());
    }

	function showInfoWindow(anchor, content) {
	  infoWindowVisible = true;
	  infoWindow.setContent(content);
	  infoWindow.open(map, anchor);
	}
	
	function closeInfoWindow() {
	  infoWindow.close();
	  setTimeout("infoWindowVisible = false;", 100);
	}

    function initialize() {
      var myOptions = {
        zoom: 16,
        center: homePoint,
        mapTypeId: google.maps.MapTypeId.HYBRID
      };
      map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
	  
        google.maps.event.addListener(map, "click", mapClicked);
        reloadWaypointsHeader();
        map.setCenter(homePoint, 16);
        if (homePoint.lat() == 0 && homePoint.lng() == 0) {
          // The default home point needs a higher zoom level, out in the middle of the ocean. Images are only available from 9.
          map.setZoom(2);
        }
		do_resize();
    }

    function reloadWaypointsHeader(){
	  closeInfoWindow();
      getHomePoint();
      reloadWaypoints();
      reloadCameraPoints();
      redrawOverlays();
    }      
/*
This event is fired when the user clicks on the map with the mouse. A click event passes different 
arguments based on the context of the click, and whether or not the click occured on a clickable 
overlay. If the click does not occur on a clickable overlay, the overlay argument is null and the 
latlng argument contains the geographical coordinates of the point that was clicked. If the user 
clicks on an overlay that is clickable (such as a google.maps.Marker, GPolygon, GPolyline, or 
GInfoWindow), the overlay argument contains the overlay object, while the overlaylatlng argument 
contains the coordinates of the clicked overlay. In addition, a click event is then also fired on 
the overlay itself.
*/
    function mapClicked(mouseEvent) {
      if (infoWindowVisible) {
		closeInfoWindow();
		return;
      }
	  else if (waypointsHaveFocus) {
		  document.getElementById("waypoints_h").blur();
		  return;
	  }
	  var anchor = false;
      var l = mouseEvent.latLng;
      if (overlayArray) {
        for (i in overlayArray) {
          var p = overlayArray[i].get("position");
          if (p && l && p.equals(l)) {
          	anchor = overlayArray[i];
          	break;
          }
        }
      }
	  if (!anchor) {
		document.getElementById("waypoints_h").blur();
		  
          switch(clickMode) {
			  case "waypoint":
				addWaypointG(l);
				writeWaypoints();
				break;
			  case "camera":
				addCameraPointG(l);
				writeCameraPoints();
				document.form1.options_camera_view_name.value = "CAM_VIEW_" + cameras.length;
				break;
          }
          redrawOverlays();
	  }
    }

    function markerMoved(){
      //reloadWaypointsHeader();
      redrawOverlays();
	  writeCameraPoints();
	  writeWaypoints();
    }
	
	function waypointsDidFocus() {
		waypointsHaveFocus = true;
	}
	
	function waypointsDidBlur() {
		waypointsHaveFocus = false;
		reloadWaypointsHeader();
	}
	
    function redrawOverlays(){
      var ep1;
      var ep2;

      clearOverlays();
      addOverlay(homeMarker);
	  
      var cvDiv = document.getElementById('defaults_camera_view');
      if (cvDiv)
        cvDiv.innerHTML = writeCameraViewsSelect(); // TODO: selected value.
      if(document.form1.options_show_camera_points && document.form1.options_show_camera_points.checked){
        for (var i = 1; i < cameras.length; i++) { // we don't draw the camera point for CAM_VIEW_LAUNCH
          addOverlay(cameras[i]);
        }
      }
	  if (waypoints.length > 0) {
        for (var i = 0; i < waypoints.length; i++) {
          addOverlay(waypoints[i]);
          ep2 = waypoints[i].getPosition();
		  if (i > 0) {
            if(document.form1.options_show_camera_points && document.form1.options_show_camera_views.checked){
              var camView = getCameraViewpoint(waypoints[i].UDBcamView);
              if (camView) { // can't do much if we don't know this view point
                var polygon = new GPolygon([ ep1, camView.getPosition(), ep2, ep1 ], "#003ff3", 3, 0.5, "#0000ff", 0.2); // make sure to close the polygon
                addOverlay(polygon);
              }
            }
            var polyline = new google.maps.Polyline({path: [ep1, ep2], strokeColor: "#ff0000", strokeWeight: 10});
            addOverlay(polyline);
          }
		  ep1 = ep2;
        }
	  }
    }

    function getCameraViewpoint(name)
    {
      for(var i = 0; i < cameras.length; i++) { // is there a better way?
        if (cameras[i].UDBname == name)
        {
          return cameras[i];
        }
      }
      return null;
    }

		function writeWaypoints(){
			var indent = "\t";
			var myWaypoints = "const struct waypointDef waypoints[] = {\n";
			for (var i = 0; i < waypoints.length; i++) {
				var latLng = waypoints[i].getPosition();
				var alt = waypoints[i].UDBalt;
				var flags = waypoints[i].UDBflags;
				var camView = waypoints[i].UDBcamView;
				var lng = 0;
				var lat = 0;
				//TODO: Test that camera view is valid?
				if(flags.indexOf("F_ABSOLUTE") > -1) {
					lng = parseInt(latLng.lng()*10000000);
					lat = parseInt(latLng.lat()*10000000);
					/* disabled for release
					 if(camView.indexOf("_ABS") != camView.length - 4){
					 camView += "_ABS";
					 }
					 */
				} else { // relative waypoints
					var l = absoluteToRelative(latLng);
					lng = l.we;
					lat = l.sn;
					/* disabled for release
					 if(camView.indexOf("_REL") != camView.length - 4){
					 camView += "_REL";
					 }
					 */
				}
				myWaypoints = myWaypoints + indent + "{ { " + lng + ", " + lat + ", " + alt + " } , " + flags + " , " + camView + " } , //Waypoint " + (i+1) + "\n";
			}
			myWaypoints += "};\n";
			///alert(myWaypoints);
			var s = document.form1.waypoints_h.value;
			s = s.substring(0, waypointDefIndex+1) + myWaypoints;
			document.form1.waypoints_h.value = s;
			waypointDefLen = myWaypoints.length;
		}
		
		function reloadWaypoints(){
			clearWaypoints();
			
			// TODO: Load home waypoint from #define FIXED_ORIGIN_LOCATION   { -1219950467, 374124664 } // If no home waypoint, or if #define USE_FIXED_ORIGIN 1
			///var rFixedOrigin = /^[^/\S]*#define\s*FIXED_ORIGIN_LOCATION\s*{\s*(-?\d+),\s*(-?\d+)\s*}/sm;
			var rFixedOrigin = /^[^/\S]*#define\s*FIXED_ORIGIN_LOCATION\s*{\s*(-?\d+),\s*(-?\d+)\s*,\s*(-?\d+\.?\d?)\s*}/m;
			var m = rFixedOrigin.exec(document.form1.waypoints_h.value);
			if (m != null) {
				///alert ("Fixed origin found!");
				var lng = parseInt(m[1])/10000000;
				var lat = parseInt(m[2])/10000000;
				homePoint = new google.maps.LatLng(lat, lng);
				setHomeMarker();
				saveHomePoint();          
			}
			////      var rWaypointsDef = /^(?:\s*[^/\S]*\s*)const\s+struct\s+waypointDef\s+waypoints\s*\[\s*\]\s*=\s*{\s*({(?:[^{])*{(?:[^{])*}(?:[^{])*}(?:[^{])*)+(?:[^{])*}/sim;
			var rWaypointsDef = /^(?:\s*[^/\S]*\s*)const\s+struct\s+waypointDef\s+waypoints\s*\[\s*\]\s*=\s*{\s*({(?:[^{])*{(?:[^{])*}(?:[^{])*}(?:[^{])*)+(?:[^{])*}/im;
			var m = rWaypointsDef.exec(document.form1.waypoints_h.value);
			if (m == null) {
				alert("No waypoints found!");
				return;
			} 
			var def = m[0];
			///alert(def);
			waypointDefIndex = m.index;
			waypointDefLen = def.length;
			rWaypoint = /(?:\s*[^/\S]*\s*){\s*{\s*(-?\d+)\s*,\s*(-?\d+)\s*,\s*(-?\d+)\s*}\s*,\s*(.+?)\s*,\s*(.+?)\s*}/gi;
			var ma; // this seems to solve strange behavior on Chrome...
			while ((ma = rWaypoint.exec(def)) != null) {// match each of the waypoints in the definition found above
				///var s = "Length :" + ma.length + "\n";
				///for (var i = 0; i < ma.length; i++){
				///s += i + ":" + ma[i] + "|" + ma[i].index + "\n";
				///}
				///alert(s);
				var lng = parseInt(ma[1]);
				var lat = parseInt(ma[2]);
				var alt = ma[3];
				var flags = ma[4];
				var camView = ma[5]
				addWaypoint(lat, lng, alt, flags, camView);
			}
		}
		
		function writeCameraPoints(){
			return; // TODO: This isn't working right yet.
			var myCameras = "//Camera points\n";
			for(var i = 1; i < cameras.length; i++){ //skip the special case for CAM_VIEW_LAUNCH
				var name = cameras[i].UDBabsName;
				var latLng = cameras[i].getPosition();
				var lng = parseInt(latLng.lng()*10000000);
				var lat = parseInt(latLng.lat()*10000000);
				var alt = cameras[i].UDBalt;
				myCameras += "#define " + name + " { " + lng + "," + lat + "," + alt + " }\n";
				name = cameras[i].UDBRelName;
				//TODO: myCameras += "#define " + name + " { " + lng + "," + lat + "," + alt + " }\n";
			}
			myCameras += "//End of camera points\n";
			var s = document.form1.waypoints_h.value;
			s = s.substring(0, camerasDefIndex) + myCameras + s.substring(camerasDefIndex+camerasDefLen);
			document.form1.waypoints_h.value = s;
			camerasDefLen = myCameras.length;
		}
		
		function reloadCameraPoints(){
			camerasDefIndex = waypointDefIndex;
			camerasDefLen = 0;
			clearCameraPoints();
			var r = /^\/\/Camera points/gmi;
			var m = r.exec(document.form1.waypoints_h.value);
			if (m == null) {
				//alert("No start of camera points found.");
				return;
			}
			camerasDefIndex = m.index;
			r = /^\/\/End of camera points/gmi;
			m = r.exec(document.form1.waypoints_h.value);
			if (m == null) {
				alert("No end to camera points found.");
				return;
			}
			camerasDefLen = m.index - camerasDefIndex + 22;
			var def = document.form1.waypoints_h.value.substring(camerasDefIndex, camerasDefIndex + camerasDefLen);
			var r = /(?:\s*)#define(?:\s+)(\S+)(?:\s*){\s*(-?\d+)\s*,\s*(-?\d+)\s*,\s*(\d+)\s*}/gi; 
			
			while ((m = r.exec(def)) != null) {// match each of the camera points in the definition found above
				var name = m[1]; // TODO: variants of a name (_REL / _ABS)
				var lng = parseInt(m[2])/10000000;
				var lat = parseInt(m[3])/10000000;
				var alt = m[4];
				addCameraPoint(name, lat, lng, alt);
			}
		}
		
		function addWaypointG(latLng){
			var defaultAlt = document.form1.defaults_altitude.value;
			var defaultCamView = document.form1.defaults_camview.value;
			var defaultFlags = getFlagsFromCode(document.form1);
			if (defaultFlags.indexOf("F_ABSOLUTE") > -1) { // Absolute waypoint
				addWaypoint(latLng.lat() * 10000000, latLng.lng() * 10000000, defaultAlt, defaultFlags, defaultCamView);
			} else { // relative waypoint
				var l = absoluteToRelative(latLng);
				addWaypoint(l.sn, l.we, defaultAlt, defaultFlags, defaultCamView);        
			}
		}
		
		function addWaypoint(lat, lng, alt, flags, camView){
			var index = waypoints.length;
			var letter = String.fromCharCode("A".charCodeAt(0) + index);
			///alert("About to add waypoint " + index + " (" + letter + ") at (" + lat +", "+lng+", "+flags+", "+camView);
			/////      var myIcon = new GIcon(baseIcon);
			
			var myImage = "https://raw.githubusercontent.com/googlemaps/js-v2-samples/gh-pages/markers/red/marker" + (index+1) + ".png"; // TODO: Set image based on flags
			
			var latlng;
			
			if(flags.indexOf("F_ABSOLUTE") > -1) {
				latlng = new google.maps.LatLng(lat/10000000, lng/10000000);
			} else { // relative waypoints
				var l = new relativeCordinates();
				l.we = lng;
				l.sn = lat;        
				latlng = relativeToAbsolute(l);
			}
			var marker = new google.maps.Marker({position: latlng, draggable: true, icon:myImage});
			marker.UDBIndex = index;
			marker.UDBalt = alt;
			marker.UDBflags = flags;
			marker.UDBcamView = camView;
			if((marker.UDBcamView.indexOf("_ABS") == marker.UDBcamView.length - 4) | (marker.UDBcamView.indexOf("_REL") == marker.UDBcamView.length - 4)) {
				marker.UDBcamView = marker.UDBcamView.substr(0, marker.UDBcamView.length - 4);
			}
			google.maps.event.addListener(marker, "dragstart", function() {
										  closeInfoWindow();
										  });
			google.maps.event.addListener(marker, "dragend", markerMoved);
			google.maps.event.addListener(marker, "click", markerClick);
			waypoints[waypoints.length] = marker;
		}
		
		function addCameraPointG(latLng){
			addCameraPoint(document.form1.options_camera_view_name.value, latLng.lat(), latLng.lng(), 0);
		}
		
		function addCameraPoint(name, lat, lng, alt){
			if(name.indexOf("_ABS") == name.length - 4){
				name = name.substr(0, name.length - 4);
			}
			if(name.indexOf("_REL") == name.length - 4){
				name = name.substr(0, name.length - 4);
			}
			//TODO: Make sure name is unique
			var index = cameras.length;
			var myIcon = new GIcon(baseIcon);
			myIcon.image = "https://raw.githubusercontent.com/googlemaps/js-v2-samples/gh-pages/markers/red/marker" + index + ".png";
			var latlng = new google.maps.LatLng(lat, lng);
			var marker = new google.maps.Marker({position: latlng, draggable: true, icon:myIcon});
			marker.UDBname = name;
			marker.UDBrelName = name + "_REL";
			marker.UDBabsName = name + "_ABS";
			marker.UDBalt = alt;
			cameras[cameras.length] = marker;
			google.maps.event.addListener(marker, "dragstart", function() {
										  closeInfoWindow();
										  });
			google.maps.event.addListener(marker, "dragend", markerMoved);
			google.maps.event.addListener(marker, "click", cameraClick);
		}
		
		var wpEditIndex;
		var wpEditAlt;
		var wpEditFlags;
		var wpEditCamView;
		
		function changeWaypoint(){
			if (wpEditIndex == null){
				alert("Error: Call to changeWaypoint without setting parameters!");
				return;
			}
			var editForm = document.editMarker;
			var marker = waypoints[wpEditIndex];
			marker.UDBalt = editForm.alt.value;
			marker.UDBflags = getFlagsFromCode(editForm);
			marker.UDBcamView = editForm.camView.value;
			//TODO: Update marker icon for new color.
			closeInfoWindow();
			wpEditIndex = wpEditAlt = wpEditFlags = wpEditCamView = null;
			redrawOverlays();
			writeWaypoints();
		}
		
		function deleteWaypoint(wpIndex){
			if (wpEditIndex != wpIndex) {
				alert("Error: Invalid delete attempt!");
				return;
			}
			for(var i = wpIndex; i < waypoints.length - 1; i ++) {
				waypoints[i] = waypoints[i+1];
			}
			closeInfoWindow();
			waypoints.pop();
			writeWaypoints();
			reloadWaypoints();
			redrawOverlays();
		}
		
		function getFlagsFromCode(form)
		{
			var flags = "";
			try {
				if (form.flag_f_normal.checked)
				flags += "F_NORMAL + ";
				if (form.flag_f_absolute.checked)
				flags += "F_ABSOLUTE + ";
				if (form.flag_f_inverted.checked)
                flags += "F_INVERTED + ";
				if (form.flag_f_hover.checked)
                flags += "F_HOVER + ";
				if (form.flag_f_land.checked)
                flags += "F_LAND + ";
				if (form.flag_f_loiter.checked)
                flags += "F_LOITER + ";
				if (form.flag_f_trigger.checked)
                flags += "F_TRIGGER + ";
				if (form.flag_f_altitude_goal.checked)
                flags += "F_ALTITUDE_GOAL + ";
				/*
				 if (form..checked)
				 flags += " + ";
				 */
				if (flags.length > 3)
				{
					flags = flags.substr(0, flags.length - 3); // get rid of the trailing +
				} else {
					flags = "F_NORMAL";
				}
				return flags;
			} catch (err) {
				alert ("Error parsing flags from HTML.\n" + form.innerHtml + "\n" + err);
				return null;
			}
		}
		
	
    function clearWaypoints(){
      waypoints = new Array();
    }
	
    function clearCameraPoints(){
      cameras = new Array();
      cameras[0] = new google.maps.Marker({position: homePoint});
      cameras[0].UDBName = "CAM_VIEW_LAUNCH";
      cameras[0].UDBRelName = "CAM_VIEW_LAUNCH_REL";
      cameras[0].UDBAbsName = "CAM_VIEW_LAUNCH_ABS";
    }

    // Removes the overlays from the map, but keeps them in the array
    function removeOverlays(){
      if (overlayArray) {
        for (i in overlayArray) {
        	overlayArray[i].setMap(null);
        }
      }
    }

    // Removes the overlays from the map, and empties the overlaysArray
    function clearOverlays(){
      removeOverlays();
      overlayArray.length = 0;      
    }
  
    function addOverlay(overlay) {
      overlay.setMap(map);
      overlayArray.push(overlay);
    }

    function relativeCordinates(){} // placeholder to make an object
    
    function absoluteToRelative(latLng)
    {
      var l = new relativeCordinates(); // object to hold relative offsets
      l.we = Math.round((latLng.lng() - homePoint.lng()) * (Math.cos((homePoint.lat()/360)*2*Math.PI)) / 0.000009); // how many meters south (negative) or north of home point
      l.sn = Math.round((latLng.lat() - homePoint.lat()) / 0.000009); // how many meters west (negative) or east of home point
      return l;
    }

    function relativeToAbsolute(l)
    {
        var homeLat = homePoint.lat();
        var homeLng = homePoint.lng();
        var lat = (homeLat + (l.sn * 0.000009)); // how many meters west (negative) or east of home point
        var lng = (homeLng + ((l.we * 0.000009)/(Math.cos((homeLat/360)*2*Math.PI)))); // how many meters south (negative) or north of home point
        return new google.maps.LatLng(lat, lng);
    }
    
    var wpEditIndex;
    var wpEditAlt;
    var wpEditFlags;
    var wpEditCamView;

    function cameraClick(){
      showInfoWindow(this, this.UDBName + "<br />(" + this.UDBRelName + "<br />" + this.UDBAbsName +")");
    }

    function markerClick(){
      wpEditIndex = this.UDBIndex;
      wpEditAlt = this.UDBalt;
      wpEditFlags = this.UDBflags;
      wpEditCamView = this.UDBcamView;
      var s = "<form name='editMarker' value='editMarker' action='javascript:void(0);'><table>";
      s += "<tr><td colspan='2'>Waypoint #" + (wpEditIndex + 1) + "</td></tr>";
      s += "<tr><td colspan='2'>Altitude: <input type='text' name='alt' id='alt' value='" + wpEditAlt + "'/></td></tr>";
      s += "<tr><td>";
      s += writeFlagsCode(wpEditFlags);
      s += "</td></tr>";
      s += "<tr><td colspan='2'>CameraView: <input type='text' name='camView' id='camView' value='" + wpEditCamView + "'/></td></tr>";
		s += "<tr><td><input type='submit' value='Delete' onClick='deleteWaypoint(" + wpEditIndex + "); return false;'/></td>";
		s += "<td><input type='submit' value='Save' onClick='changeWaypoint(); return false;'/></td></tr>";
      s += "</table></form>";
      showInfoWindow(this, s);
    }

    function writeFlagsCode(flags)
    {
        var s = "<table>";
        s += "<tr>";
        s += "<td><input type='checkbox' name='flag_f_normal' id='flag_f_normal'";
        if (flags.indexOf("F_NORMAL") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_NORMAL</td>";
        s += "<td><input type='checkbox' name='flag_f_absolute' id='flag_f_absolute'";
        if (flags.indexOf("F_ABSOLUTE") > -1) {
			s += " checked='YES' " 
        }
        s += "/></td><td>F_ABSOLUTE</td>";
        s += "</tr>";
        s += "<tr>";
        s += "<td><input type='checkbox' name='flag_f_inverted' id='flag_f_inverted'";
        if (flags.indexOf("F_INVERTED") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_INVERTED</td>";
        s += "<td><input type='checkbox' name='flag_f_hover' id='flag_f_hover'";
        if (flags.indexOf("F_HOVER") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_HOVER</td>";
        s += "</tr>";
        s += "<tr>";
        s += "<td><input type='checkbox' name='flag_f_land' id='flag_f_land'";
        if (flags.indexOf("F_LAND") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_LAND</td>";
        s += "<td><input type='checkbox' name='flag_f_loiter' id='flag_f_loiter'";
        if (flags.indexOf("F_LOITER") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_LOITER</td>";
        s += "</tr>";
        s += "<tr>";
        s += "<td><input type='checkbox' name='flag_f_trigger' id='flag_f_trigger'";
        if (flags.indexOf("F_TRIGGER") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_TRIGGER</td>";
        s += "<td><input type='checkbox' name='flag_f_altitude_goal' id='flag_f_altitude_goal'";
        if (flags.indexOf("F_ALTITUDE_GOAL") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_ALTITUDE_GOAL</td>";
        s += "</tr>";
        s += "</table>";
        return s;
    }

    function writeCameraViewsSelect(selected)
    {
      var s = "<select name='camera_view' id='camera_view'>";
      for(var i = 0; i < cameras.length; i++){
          var name = cameras[i].UDBName;
          s += "<option ";
          if (name == selected)
            s += "selected='y'";
          s += ">" + name + "</option>";
      }
      s += "</select>";
      return s;
    }

    function set_cookie ( name, value, exp_y, exp_m, exp_d, path, domain, secure ){
      try {
        var cookie_string = name + "=" + escape ( value );
        if (exp_y) {
          var expires = new Date ( exp_y, exp_m, exp_d );
          cookie_string += "; expires=" + expires.toGMTString();
        }
        if (path)
          cookie_string += "; path=" + escape ( path );
        if (domain)
          cookie_string += "; domain=" + escape ( domain );
        if (secure)
          cookie_string += "; secure";
        document.cookie = cookie_string;
        try {
          localStorage.setItem(name, value);
        } catch (err) {
      	  alert("Error: Couldn't use local storage either!");
      	}
      } catch(err) {
        alert("Error saving cookie.\n" + err);
      }
    }

    function get_cookie ( cookie_name ) {
      var results = document.cookie.match ( '(^|;) ?' + cookie_name + '=([^;]*)(;|$)' );
      if (results)
      {
        return (unescape(results[2]));
      }
      try {
        results = localStorage.getItem(cookie_name);
        return (unescape(results));
      } catch (err) { }
      return null;
    }


function setSelectionRange(input, selectionStart, selectionEnd) {
  if (input.setSelectionRange) {
    input.focus();
    input.setSelectionRange(selectionStart, selectionEnd);
  }
  else if (input.createTextRange) {
    var range = input.createTextRange();
    range.collapse(true);
    range.moveEnd('character', selectionEnd);
    range.moveStart('character', selectionStart);
    range.select();
  }
}

function replaceSelection (input, replaceString) {
	if (input.setSelectionRange) {
		var selectionStart = input.selectionStart;
		var selectionEnd = input.selectionEnd;
		input.value = input.value.substring(0, selectionStart)+ replaceString + input.value.substring(selectionEnd);
    
		if (selectionStart != selectionEnd){ 
			setSelectionRange(input, selectionStart, selectionStart + 	replaceString.length);
		}else{
			setSelectionRange(input, selectionStart + replaceString.length, selectionStart + replaceString.length);
		}

	}else if (document.selection) {
		var range = document.selection.createRange();

		if (range.parentElement() == input) {
			var isCollapsed = range.text == '';
			range.text = replaceString;

			 if (!isCollapsed)  {
				range.moveStart('character', -replaceString.length);
				range.select();
			}
		}
	}
}


// We are going to catch the TAB key so that we can use it, Hooray!
function catchTab(item,e){
	if(navigator.userAgent.match("Gecko")){
		c=e.which;
	}else{
		c=e.keyCode;
	}
	if(c==9){
		replaceSelection(item,String.fromCharCode(9));
		setTimeout("document.getElementById('"+item.id+"').focus();",0);	
		return false;
	}
		    
}


function getActualStyle(a) {
	if (document.defaultView && document.defaultView.getComputedStyle){
		return document.defaultView.getComputedStyle(a,"");
	}
	else
		return a.style;
}


// FIXME: Replace magic numbers with live values of frame margins, etc.
function do_resize() {
	try {
		var htmlheight = document.body.parentNode.clientHeight;
		var htmlwidth = document.body.parentNode.clientWidth;
		
		var options_height = document.getElementById("udb_options").offsetHeight;
		
		var wframe = document.getElementById("waypoints_h");
		wframe.style.height = (htmlheight - 105 - options_height) + "px";
		var wstyle = getActualStyle(wframe);
		var wwidth = wstyle.getPropertyValue("width").replace(/px/, "");
		
		var mframe = document.getElementById("map_canvas");
		mframe.style.height = (htmlheight - 15) + "px";
		mframe.style.width = (htmlwidth - wwidth - 30) + "px";
	}
	catch(err) {
		// alert(err);
	}
}

    </script>
  </head>

  <body onload="initialize()" onresize="do_resize()">
   <form name="form1" id="form1" method="post" action="javascript:void(0)">
	<table border="0">
	<tr>
	<td valign="top">
		<h2>UDB Waypoint Editor <a target="_blank" href="https://github.com/MatrixPilot/MatrixPilot/blob/master/MatrixPilot/waypoints.h">[Reference]</a></h2>
        <textarea name="waypoints_h" id="waypoints_h" rows="60" cols="55" wrap="off" onFocus="waypointsDidFocus();" onBlur="waypointsDidBlur();" onkeydown="return catchTab(this,event)" style="font-family: monospace;">
////////////////////////////////////////////////////////////////////////////////
// This is an example course that makes a 100 meter square, 75 meters above the starting point, and
// then takes a photo and lands. Updated 20100629 to be centered over the origin.
// 
// We first go to the south east corner of the square.
// Then on to the north east corner.
// The plane then uses ailerons to flip upside down, and heads towards the north west corner.
// Then we flip back over and head back to the south west corner.  
// 
// The pattern will keep repeating as long as the UDB is in waypoint mode.

const struct waypointDef waypoints[] = {
	{ { 50, -50, 75 } , F_NORMAL , CAM_VIEW_LAUNCH } , //Waypoint 1
	{ { 50, 50, 75 } , F_NORMAL , CAM_VIEW_LAUNCH } , //Waypoint 2
	{ { -50, 50, 75 } , F_INVERTED , CAM_VIEW_LAUNCH } , //Waypoint 3
	{ { -50, -50, 75 } , F_NORMAL , CAM_VIEW_LAUNCH } , //Waypoint 4
};
</textarea>
		
		<div id="udb_options" style="">
			<h3>New Waypoint Default Settings</h3>
			<script language="javascript" type="text/javascript">document.write(writeFlagsCode("F_NORMAL"));</script> <br/>
			Altitude <input type="text" name="defaults_altitude" id="defaults_altitude" value="50" /> <br/>
			Camera View Point <input type="text" name="defaults_camview" id="defaults_camview" value="CAM_VIEW_LAUNCH"/>
		</div>
	</td>
		<td valign="top">
			<div id="map_canvas" style="width: 800px; height: 800px"></div>
		</td></tr>
	</table>   
   </form>
  </body>
</html>
